package de.imdb250junkie.imdb;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import de.imdb250junkie.locale.LocaleUtils;
import de.imdb250junkie.utils.Movie;

/**
 * Utillity class for creating {@link Movie} objects from imdb html pages using
 * the imdb id.
 * 
 * @author André Stannek
 * @version 2010-02-11
 */
final class MovieMaker
{
    /**
     * masking public default constructor of utility class.
     */
    private MovieMaker()
    {

    }

    /**
     * Creates a {@link Movie} object containing data from the movie specified
     * by it's imdb id.
     * 
     * @param imdbID
     *            the IMDB ID
     * @param page
     *            html page
     * @return the {@link Movie} object
     */
    public static Movie getMovie(final String imdbID, final String page)
    {
        final Movie movie = new Movie();

        movie.setOriginalTitle(getTitle(page));
        movie.setYear(getYear(page));
        movie.setRank(getRank(page));
        movie.setRating(getRating(page));
        try
        {
            movie.setLocalizedTitle(getLocalizedTitle(new URL(
                    "http://www.imdb.com/title/" + imdbID + "/releaseinfo")));
        }
        catch (final MalformedURLException e1)
        {
            movie.setLocalizedTitle("error while loading title");
        }
        try
        {
            movie.setLink(new URL("http://www.imdb.com/title/" + imdbID));
        }
        catch (final MalformedURLException e)
        {
            movie.setLink(null);
        }

        return movie;
    }

    /**
     * Parses the html page searching for the german title of the movie.
     * 
     * @param url
     *            the URL to the movie
     * @return the german title of the movie or "N/A" if the german title is not
     *         available.
     */
    private static String getLocalizedTitle(final URL url)
    {
        return getLocalizedTitle(url, 10);
    }

    /**
     * 
     * @param url
     *            the page url
     * @param tries
     *            the number of tries already used to fetch the page
     * @return the localized title
     */
    private static String getLocalizedTitle(final URL url, final int tries)
    {
        try
        {
            // exponetial backoff
            Thread.sleep(10000 / tries);
        }
        catch (final InterruptedException e2)
        {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }
        String webPage;
        String result = "N/A";
        try
        {
            webPage = HTMLInterface.decode(HTMLInterface.fetch(url));
            final String country = ResourceBundle.getBundle(
                    "de.imdb250junkie.locale.GUIStrings",
                    LocaleUtils.getLocale()).getString("country");

            final Matcher matcher = Pattern.compile(
                    "<td>(.*)</td>\\n\\n<td>(.*)" + country + "(.*)</td>",
                    Pattern.MULTILINE).matcher(webPage);

            if (matcher.find())
            {
                result = HTMLInterface.decode(matcher.group(1)).trim();
            }
        }
        catch (final IOException e)
        {
            if (tries > 0)
            {
                result = getLocalizedTitle(url, tries - 1);
            }
        }
        return result;

    }

    /**
     * Parses the html page searching for the original title of the movie.
     * 
     * @return the title or an error message if the title could not be parsed
     * @param page
     *            the web page
     */
    private static String getTitle(final String page)
    {
        final Matcher matcher = Pattern.compile("<h1>(.*)<span>",
                Pattern.MULTILINE).matcher(page);

        if (matcher.find())
        {
            return HTMLInterface.decode(matcher.group(1)).trim();
        }
        else
        {
            return ResourceBundle.getBundle(
                    "de.imdb250junkie.locale.GUIStrings",
                    LocaleUtils.getLocale()).getString("titel_not_found");
        }
    }

    /**
     * Parses the html page searching for the publishing year of the movie.
     * 
     * @return the publishing year or 0 if the year could not be parsed
     * @param page
     *            the web page
     */
    private static int getYear(final String page)
    {
        final Matcher matcher = Pattern.compile(
                "<title>.* \\(([0-9]*)\\)</title>", Pattern.MULTILINE).matcher(
                page.replaceAll("\n", ""));

        if (matcher.find())
        {
            return Integer.parseInt(matcher.group(1));
        }
        else
        {
            return 0;
        }
    }

    /**
     * Parses the html page searching for the rank of the movie.
     * 
     * @return the rank or 0 if the rank could not be parsed
     * @param page
     *            the web page
     */
    private static int getRank(final String page)
    {
        final Matcher matcher = Pattern.compile("Top 250: #([0-9]*)",
                Pattern.MULTILINE).matcher(page);

        if (matcher.find())
        {
            return Integer.parseInt(matcher.group(1));
        }
        else
        {
            return 0;
        }
    }

    /**
     * Parses the html page searching for the rating of the movie.
     * 
     * @return the rating or 0.0 if the rating could not be parsed
     * @param page
     *            the web page
     */
    private static float getRating(final String page)
    {
        // rating part in the html file on Feb. 9th, 2010
        // <div class="starbar-meta">
        // <b>9.2/10</b>
        final Matcher matcher = Pattern.compile(
                "<div class=\"starbar\\-meta\">\n<b>([1-9])\\.([0-9])/10</b>",
                Pattern.MULTILINE).matcher(page);

        int full;
        int tenth;
        if (matcher.find())
        {
            full = Integer.parseInt(matcher.group(1));
            tenth = Integer.parseInt(matcher.group(2));
        }
        else
        {
            full = 0;
            tenth = 0;
        }
        return full + (tenth / 10f);
    }
}
